package com.thams.util.pageUtil.core;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ibatis.sqlmap.engine.execution.SqlExecutor;
import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback;
import com.ibatis.sqlmap.engine.scope.StatementScope;
import com.thams.util.pageUtil.dialect.i.Dialect4Ibatis;

/**
 * @author: luyu
 * @date: Sep 9, 2008
 *  
 * @Function:继承ibatis的 SqlExecutor并覆盖executeQuery方法.<br>
 * 		其实等于利用代理模式去实现sql语句层面的分页.主要利用java的反射机制破除sqlExecutor的保护的set方法
 */
public class PageSqlExecutor extends SqlExecutor {
	/**
	 * @author: luyu
	 * @date: Sep 9, 2008
	 *  
	 * @Function: 拼装包装分页sql语句 然后调用父类IBATIS的执行语句
	 */
	public void executeQuery(StatementScope statementScope, Connection conn,
			String sql, Object[] parameters, int pager, int pageSize,
			RowHandlerCallback callback, Object parameterObject)
			throws SQLException {
		judgeDataBaseType(conn);//调用判断数据库 注入不同的分页方言

		//判断是  pager和pageSize是否有.如果为空直接调用父类执行.说明没有分页的要求
		if ((pager != NO_SKIPPED_RESULTS || pageSize != NO_MAXIMUM_RESULTS)
				&& supportsLimit()) {

			//判断目标页面为0的时候赋值为1
			if (pageSize == 0) {
				pageSize = 1;
			}

			String primaryKey = "";
			String orderBySubStr = "";
			//从parameterObject 获取参数
			if (parameterObject instanceof Map) {
				orderBySubStr = (String) ((Map) parameterObject).get("orderBy");
				primaryKey = (String) ((Map) parameterObject).get("primaryKey");
			}
			if (StringUtils.isEmpty(primaryKey)) {//传入是Map的话会 要求orderBy和primarykey等字段
//				primaryKey = DEFAULT_PRIMARYKEY;
			}

			//拼凑分页语句
			sql = dialect.getLimitString(sql, pager, pageSize, primaryKey,
					orderBySubStr);

			if (logger.isDebugEnabled()) {
				logger.debug(sql);
			}
			pager = NO_SKIPPED_RESULTS;
			pageSize = NO_MAXIMUM_RESULTS;
		}
		//TODO: 扩展ibatis分页框架 打印调试语句
		//System.out.println("---com.thams.framework.pageUtil.core.PageSqlExecutor: "+ sql);
		super.executeQuery(statementScope, conn, sql, parameters, pager,
				pageSize, callback, parameterObject);
	}

	/**
	 *  默认主键.主要为sqlserver数据库和档案系统考虑.因为本系统大多是使用did为主键.其他数据库不用考虑
	 */
	public static final String DEFAULT_PRIMARYKEY = "DID";

	/**
	 * @author: luyu
	 * @data: Sep 9, 2008
	 * @return
	 *
	 * @function: 判断是否支持分页,如果没有方言 就 不允许
	 */
	public boolean supportsLimit() {
		if (enableLimit && dialect != null) {
			return dialect.supportsLimit();
		}
		return false;
	}

	//日志
	public static final Log logger = LogFactory.getLog(PageSqlExecutor.class);
	//sqlserver方言 从connect..getMetaData().getDatabaseProductName()来获得
	public static final String MICROSOFT_SQL_SERVER = "Microsoft SQL Server";
	//oracle方言 从connect..getMetaData().getDatabaseProductName()来获得
	public static final String ORACLE_DATABASE = "Oracle";
	//mysql方言 从connect..getMetaData().getDatabaseProductName()来获得
	public static final String MYSQL_DATABASE = "mysql";

	//判断数据库类型.注入不同的dialect
	private void judgeDataBaseType(Connection conn) throws SQLException {
		DataBase_Type = conn.getMetaData().getDatabaseProductName();
		if (DataBase_Type.equalsIgnoreCase(MICROSOFT_SQL_SERVER)) {
			dialect = sqlServerDialect;
		} else if (DataBase_Type.equalsIgnoreCase(ORACLE_DATABASE)) {
			dialect = oracleDialect;
		} else if (DataBase_Type.equalsIgnoreCase("MYSQL_DATABASE")) {//mysql的没写
			dialect = mySqlDialect;
		}
	}

	private String DataBase_Type = ""; //方便得到数据库类类型 
	private Dialect4Ibatis mySqlDialect;
	private Dialect4Ibatis oracleDialect;
	private Dialect4Ibatis sqlServerDialect;
	private Dialect4Ibatis dialect;

	/**
	 * 默认允许分页
	 */
	private boolean enableLimit = true;

	public boolean isEnableLimit() {
		return enableLimit;
	}

	public void setEnableLimit(boolean enableLimit) {
		this.enableLimit = enableLimit;
	}

	public void setMySqlDialect(Dialect4Ibatis mySqlDialect) {
		this.mySqlDialect = mySqlDialect;
	}

	public void setOracleDialect(Dialect4Ibatis oracleDialect) {
		this.oracleDialect = oracleDialect;
	}

	public void setSqlServerDialect(Dialect4Ibatis sqlServerDialect) {
		this.sqlServerDialect = sqlServerDialect;
	}

}
